module mculib.arm.nvic;
/**
* 中断管理
*/
import mculib.chip;

version(None):

private enum bool hasBusPeriph = HasPeriph!("NVIC");

static if(hasBusPeriph):
import arm.bus;
import arm.cortex_m;
//import baremetal:RW_Reg;
import arm.volatile;
import arm.conf;




static interface NVIC //: MMIOBus!(Peripherals.NVIC)
{
    private
    {
        enum NVIC_Type* mBase = Peripherals.NVIC;
        enum string IFName = "NVIC";
        //alias volatileUByte = volatile!ubyte;


    }
    /// 触发中断

    /// 设置优先级
    static void PrioritySet(IRQn_Ext mIrq,uint mPriority)
    in(mIrq > 0,"IRQ must > 0")
    {
        enum addr = cast(size_t)(mBase) + (mBase.IPR0.offsetof);
        auto ptr = cast(ubyte*)(addr + mIrq);
        auto nval = cast(ubyte)(mPriority << (8 - PriorityWidth));

        auto reg = cast(volatileUByte*)ptr;

        *reg = nval;        

        //MMIO_RegSet(ptr,nval);        
    }
    /// 获取优先级
    static uint PriorityGet(IRQn_Ext mIrq)
    in(mIrq > 0,"IRQ must > 0")
    {
        enum addr = cast(size_t)(mBase) + (mBase.IPR0.offsetof);
        auto ptr = cast(ubyte*)(addr + mIrq);
        //auto val = MMIO_RegGet(ptr);
        //auto reg = cast(RW_Reg!(null,ubyte)*)ptr;
        auto reg = cast(volatileUByte*)ptr;
        
        auto val = *reg;

        return cast(uint)(val >> (8 - PriorityWidth));
    }
    /// 断模板
    package{
        /// 使能中断
        pragma(inline,__Inline)
        static void EnableIRQ(IRQn_Ext mIrq)()
        {
            // 计算偏移地址
            enum volatileUByte* ptr = cast(volatileUByte*)(cast(size_t)&mBase.ISER0 + (mIrq >> 5u)*4);
            // 设置位
            ptr[mIrq&0x1f] = 1;

        }
        /// 禁用中断
        pragma(inline,__Inline)
        static void DisableIRQ(IRQn_Ext mIrq)()
        {
            // 计算偏移地址
            enum volatileUByte* ptr = cast(volatileUByte*)(cast(size_t)&mBase.ICER0 + (mIrq >> 5u)*4);
            // 设置位
            ptr[mIrq&0x1f] = 1;
        }
        /// 触发中断
        pragma(inline,__Inline)
        static void SetPendingIRQ(IRQn_Ext mIrq)()
        {
            // 计算偏移地址
            enum volatileUByte* ptr = cast(volatileUByte*)(cast(size_t)&mBase.ISPR0 + (mIrq >> 5u)*4);
            // 设置位
            ptr[mIrq&0x1f] = 1;
        }
        /// 清除中断
        pragma(inline,__Inline)
        static void ClearPendingIRQ(IRQn_Ext mIrq)()
        {
            // 计算偏移地址
            enum volatileUByte* ptr = cast(volatileUByte*)(cast(size_t)&mBase.ICPR0 + (mIrq >> 5u)*4);
            // 设置位
            ptr[mIrq&0x1f] = 1;
        }
        /// 中断状态查询
        pragma(inline,__Inline)
        static bool GetActive(IRQn_Ext mIrq)()
        {
            // 计算偏移地址
            enum volatileUByte* ptr = cast(volatileUByte*)(cast(size_t)&mBase.IABR0 + (mIrq >> 5u)*4);
            // 设置位
            return ptr[mIrq&0x1f] == 1;
        }
        /// 中断优先级设置
        pragma(inline,__Inline)
        static void SetPriority(IRQn_Ext mIrq,uint mPriority)()
        {
            /*
            // 计算偏移地址
            enum vubyte* ptr = cast(vubyte*)(cast(size_t)&mBase.IPR0 + (mIrq >> 2u)*4);
            // 设置位
            ptr[mIrq&0x3] = cast(ubyte)(mPriority << (8 - PriorityWidth));
            */
        }
    }
}

//pragma(inline,true)
final abstract class CreateHandler(IRQn_Ext mIrq,IRQHandler cb)
{
    import std.traits;
    import core.attribute:optStrategy;

    //import arm.misc;
    //import std.conv : to;

    // 获取枚举值对应的常量名字符
    enum mangleStr = __traits(identifier, EnumMembers!IRQn_Ext[mIrq]) ~ "_IRQHandler";

    //pragma(msg, "中断:",__traits(identifier, cb));
    /*
    pragma(msg, "中断:",mangleStr);
    pragma(msg, "中断:",mangleStr);
    
    pragma(msg, "中断:",__traits(identifier, typeof(mIrq)));
    pragma(msg, "类型1:",typeid(mIrq).name);
    */
    //pragma(msg, "类型1:",__traits(allMembers, typeid(mIrq)));
    //pragma(msg, "回调:",mIrqPeri.IRQCallback.stringof);
    //pragma(msg, "命名:",mIrqPeri.IRQName);

    /// 使能中断
    pragma(inline,true)
    static void EnableIRQ()
    {
        NVIC.EnableIRQ!mIrq();
    }
    /// 禁用中断
    pragma(inline,true)
    static void DisableIRQ()
    {
        NVIC.DisableIRQ!mIrq();
    }
    /// 查询是否进入中断
    pragma(inline,true)
    static bool GetActive()
    {
        return NVIC.GetActive!mIrq();
    }


    /// 回调函数命名
    //@optStrategy("minsize")
    pragma(inline,true)
    pragma(mangle, mangleStr)
    extern(C)
    static void mHandler()
    {
        cb();
    }

}


version(NONE):

/**
    nvic
    向量中断优先控制

    * 0xe000e100 ~ 0xe000e4ef
    * 0xe000ef00 ~ 0xe000ef03
*/
final abstract class NVIC{
    /// 外设地址
    enum PeripheralAddress = CorePeripheralAddress.NVIC_Base;
    /// NVIC 结构体
    struct NVIC_Struct
    {
        /// 对齐
        align(1):
        /// 中断集使能寄存器
        uint[8]   ISER;
        /// 保留
        uint[24]   RESERVED0;
        /// 中断集禁止寄存器
        uint[8]   ICER;
        /// 保留
        uint[24]   RSERVED1;
        /// 中断集置位寄存器
        uint[8]   ISPR;
        /// 保留
        uint[24]   RESERVED2;
        /// 中断集清零寄存器
        uint[8]   ICPR;
        /// 保留
        uint[24]   RESERVED3;
        /// 中断激活寄存器
        uint[8]   IABR;
        /// 保留
        uint[56]   RESERVED4;
        /// 中断优先级寄存器
        ubyte[240]   IP;
        /// 保留
        uint[644]   RESERVED5;
        /// 软件触发中断寄存器 低8位有效
        uint        STIR;
    }
    /// 寄存器指针
    enum NVIC_Struct* pNVIC = RegMap!(PeripheralAddress,NVIC_Struct);

    /// 软件触发中断
    static void SoftwareTriggerInterrupt(ubyte IRQn)
    {
        //volatileStore(&pNVIC.STIR, IRQn);
    }
    /**
    * 开启中断
    * Params: 
    *   IRQn = 中断号
    */
    pragma(inline,_inline)
    static void EnableIRQ(uint IRQn)
    {
        volatileStore(&pNVIC.ISER[IRQn >> 5u],1u << (IRQn & 0x1F));
        //数据同步        
        __dsb();
        __isb();
    }
    /**
    * 关闭中断
    * Params:
    *   IRQn = 中断号
    */
    pragma(inline,_inline)
    static void DisableIRQ(uint IRQn)
    {
        volatileStore(&pNVIC.ICER[IRQn >> 5u],1u << (IRQn & 0x1F));
        //数据同步        
        __dsb();
        __isb();
    }
    /**
    * 设置中断组优先级
    */
    static void SetPriorityGrouping(IRQn_Ext IRQn,uint priority)
    in(IRQn > 0)
    {
        //ubyte mPriority = cast(ubyte)(priority << PriorityWidth);
        //p3NVIC.IP[IRQn] = cast(ubyte)(priority << PriorityWidth);
        //volatileStore
    }

    
    private
    pragma(crt_constructor,CrtPriority!(FlagCrt.NVIC,0))
    static this()
    {
        import arm.rcc;
        
    }
}








/*
PRIORITYGROUP GetPriorityGrouping()
{
    return cast(PRIORITYGROUP)SCB.AIRCR.VECTKEYSTAT.bitsType;
}

void EnableIRQ(uint IRQn)
{
    if (IRQn < 0)
    {
        SCB.SYSCTRL.bitsType |= (1 << (IRQn & 0x1F));
    }
    else
    {
        NVIC.ISER[IRQn >> 5].bitsType = (1 << (IRQn & 0x1F));
    }
}*/



